package com.puzzlebazar.client.heyawake;

import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.MouseEvent;
import com.google.gwt.event.shared.EventHandler;
import com.puzzlebazar.client.puzzle.model.History;
import com.puzzlebazar.client.puzzle.model.HistoryMove;
import com.puzzlebazar.client.puzzle.model.MoveList;
import com.puzzlebazar.client.puzzle.model.MoveTimer;
import com.puzzlebazar.client.squaregrid.control.ComponentCallbackAdapter;
import com.puzzlebazar.client.squaregrid.view.TextBoxDrawable;
import com.puzzlebazar.client.util.NumberFilter;
import com.puzzlebazar.client.util.Observable;
import com.puzzlebazar.client.util.Observer;
import com.puzzlebazar.client.util.Recti;
import com.puzzlebazar.client.util.Vec2i;

public class EditRoomValueState extends HeyawakeState implements Observer {

	private final ClickCallback clickCallback = new ClickCallback();
	private final EditCallback editCallback = new EditCallback();

	private final TextBoxDrawable textBox;

	boolean isEditing = false;
	private Room room;
	private boolean cancelEdit;
	
	/**
	 * Creates a controller state for room creation
	 * 
	 * @param model The associated model
	 * @param view The view for the heyawake
	 * @param controller The associated controller
	 * @param history History track into which to add the moves
	 * @param moveTimer The move timer
	 */
	public EditRoomValueState(HeyawakeModel model, HeyawakeView view, 
			HeyawakeController controller, History history, MoveTimer moveTimer) {
		super(model, view, controller, history, moveTimer);
		

		textBox = new TextBoxDrawable( "CRSTextBox", "" );
		textBox.setMaxLength(3);
		textBox.addKeyPressHandler( new NumberFilter() );		
		textBox.addKeyDownHandler( editCallback );
		model.addObserver( this );
	}
	
	
	@Override
	public void enter() {
		controller.enableEdit( false );
		cancelEdit = false;
		
		if( !isValidRoom() ) {
			controller.switchToCreateRooms();
			return;
		}
		
		
		try {
			Recti roomArea = room.getRoomArea();
			textBox.setText( room.getStringValue() );
			textBox.setCell( roomArea.getCell00() );
			view.getHighlightLayer().addDrawable( textBox );
			textBox.setFocus(true);
			textBox.selectAll();
			enableTextEditingCallbacks();
			isEditing = true;
		} catch (Exception exception) {
			exception.printStackTrace();
			controller.switchToCreateRooms();
		}
	}

	@Override
	public void exit() {
		controller.enableEdit( true );
		isEditing = false;
		
		try {
			updateRoomValue();
		} catch (Exception exception) {
			exception.printStackTrace();
		}
		
		
		textBox.setFocus(false);
		view.getHighlightLayer().removeDrawable( textBox.getName() );
		disableTextEditingCallbacks();
	}

	/**
	 * Change the current room value if needed.
	 * 
	 * @throws Exception
	 */
	private void updateRoomValue() throws Exception {
		if( cancelEdit || !isValidRoom() )
			return;
		
		int newValue = getTextBoxValue();
		
		if( newValue != room.getValue() ) {
			long time = moveTimer.peekTime();
			MoveList moveList = new MoveList( time );
			moveList.append( model.removeRoom( room, time ) );
			moveList.append( model.addRoom( new Room( room.getRoomArea(), newValue ), time ) );
			HistoryMove historyMove = history.addMoveToHistory( moveList, model );
			if( historyMove != null ) {
				model.notifyObservers( historyMove.getPuzzleMove() );
				history.notifyObservers( historyMove );
				moveTimer.step();
				moveTimer.notifyObservers();
			}
		}
	}

	/**
	 * @return The value contained in the textbox, -1 if empty
	 */
	private int getTextBoxValue() {
		String text = textBox.getText();
		if( text.length() == 0 ) return -1;
		return Integer.parseInt( text );
	}

	private class ClickCallback extends ComponentCallbackAdapter {
		
		@Override
		public boolean mouseDown(Vec2i loc, MouseEvent<? extends EventHandler> event ) {
			controller.switchToCreateRooms();
			return true;
		}

	}

	private class EditCallback implements KeyDownHandler {
		
		@Override
		public void onKeyDown(KeyDownEvent event) {
			int keyCode = event.getNativeKeyCode();
			if (keyCode == KeyCodes.KEY_ENTER) {
				controller.switchToCreateRooms();				
			}
		}

	}
	
	/**
	 * Turns all defaults callbacks on
	 */
	private void enableTextEditingCallbacks() {
		view.getControlDecorator().addCellCallback( clickCallback );
	}

	/**
	 * Turns all defaults callbacks off
	 */
	private void disableTextEditingCallbacks() {
		view.getControlDecorator().removeCellCallback( clickCallback );
	}


	/**
	 * Sets the room for which to edit value
	 * 
	 * @param room
	 */
	public void setRoom(Room room) {
		this.room = room;
	}


	@Override
	public void release() {
		model.deleteObserver( this );
	}


	@Override
	public void update(Observable observable, Object arg) {
		if( !isEditing )
			return;
		cancelEdit = true;
		controller.switchToCreateRooms();
	}


	/**
	 * Check that the edited room is valid within the model
	 * 
	 * @return True if the room exist and can be edited, false if not
	 */
	private boolean isValidRoom() {
		try {
			Room existingRoom;
			existingRoom = model.findRoomAt(room.getRoomArea().getCell00());
			return( existingRoom != null && existingRoom.equals( room ) );
		} catch (Exception e) {
			return false;
		}
	}


	
}
